﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TaiwuModFramework.Common.Abstract;
using TaiwuModFramework.Common.Utils;

namespace TaiwuModFramework.Common.Base {
    public class BaseLogWriter : ALogWriter {


        private static Dictionary<string, BaseLogWriter> logWriters = new Dictionary<string, BaseLogWriter>();

        public override string LogPath { get; }

        public int BuffSize { get; }

        public int Interval { get; }

        private bool flushing = false;

        private readonly Timer FlushTimer;
        private readonly List<string> LogBuff;

        /// <summary>
        /// 最大缓存500条日志，每1s Flush一次
        /// </summary>
        /// <param name="path"></param>
        public BaseLogWriter(string path) : this(path, 500, 1000) { }

        public BaseLogWriter(string path, int bufferSize, int interval) {
            LogPath = path;
            Interval = interval;
            BuffSize = bufferSize;
            LogBuff = new List<string>(bufferSize + 20);

            // 创建定时器
            FlushTimer = new Timer((state) => {
                Flush();
            }, LogPath, 0, Interval);
        }

        public static BaseLogWriter GetLogWriter(string path) {
            path = PathUtils.FormatFilePath(path);
            if(logWriters.ContainsKey(path)) {
                return logWriters[path];
            }
            // 日志文件后缀为 .log
            if(!path.EndsWith(".log")) {
                path += ".log";
            }
            var logWriter = new BaseLogWriter(path);
            logWriters[path] = logWriter;
            return logWriter;
        }



        public override void WriteLines(IEnumerable<object> lines) {
            if(lines == null || lines.Count() == 0) return;
            lock(LogBuff) {
                foreach(var line in lines) {
                    LogBuff.Add(line.ToString());
                }
                CheckBuffSize();
            }
        }

        public override void WriteLine(object o) {
            if(o == null) return;
            lock(LogBuff) {
                LogBuff.Add(o.ToString());
                CheckBuffSize();
            }
        }

        private void CheckBuffSize() {
            if(LogBuff.Count >= BuffSize) {
                Flush();
            }
        }

        /// <summary>
        /// 创建日志所在的文件夹，若已存在则不操作
        /// </summary>
        private void CreateDir() {
            var dir = Directory.GetParent(LogPath);
            if(!dir.Exists) {
                dir.Create();
            }
        }

        // 将缓存的日志写入文件
        private void Flush() {
            if(flushing) return;    // 如果正在
            lock(LogBuff) {
                CreateDir();
                if(!FileExists()) {
                    File.Create(LogPath);
                }
                if(LogBuff.Count <= 0) return;
                flushing = true;
                StringBuilder buff = new StringBuilder();
                foreach(var line in LogBuff) {
                    if(line.EndsWith("\n")) {
                        buff.Append(line);
                    } else {
                        buff.AppendLine(line);
                    }
                }
                try {
                    using(StreamWriter sw = File.AppendText(LogPath)) { // 追加日志
                        sw.Write(buff);
                        LogBuff.Clear();    // 清除已写日志
                    }
                    //break;
                } catch(Exception e) {
                    // 发生错误，一般代表当前文件正在被占用
                } finally {
                    flushing = false;   // 标记为未在读写
                }

            }
        }
    }
}
